package br.ufpa.cbcc2007.dikemon.map;

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.Sprite;
import javax.microedition.lcdui.game.TiledLayer;

import br.ufpa.cbcc2007.dikemon.engine.Engine;
import br.ufpa.cbcc2007.dikemon.map.actors.Hero;
import br.ufpa.cbcc2007.dikemon.map.actors.Talker;
import br.ufpa.cbcc2007.dikemon.map.actors.Wall;


// Carrega um mapa e retorna-o.
//  Apesar de ser uma classe estável em suas funcionalidades, sua implementação dentro dos métodos muda bastante
//  e por isso não compensa descrever o que acontece internamente
public class Loader {
	private InputStream input;

	//Construtor
	// O único parametro aceito, é o "arquivo de entrada" do mapa.
	public Loader(InputStream file) {
		this.input = file;
	}
	
	//Método que carrefa o mapa e retorna. O tilesize geralmente terá valor igual a Engine.TILESIZE
	public Map load(int tileSize) {
		DataInputStream dataIn = new DataInputStream(input);
		byte buffer[] = new byte[6];
		int width, height;
		String tileset;
		Map result =  null;
		try {
			dataIn.read(buffer, 0, 6);
			width = dataIn.readInt();
			height = dataIn.readInt();
			tileset = dataIn.readUTF();
			result =  new Map(width, height, Image.createImage("/tileset/"+tileset), tileSize, tileSize);
			TiledLayer bottom = result.getBottom();
			TiledLayer middle = result.getMiddle();
			TiledLayer top = result.getTop();
			for(int i =0; i < height; ++i){
				for(int j=0; j< width; ++j){
					bottom.setCell(j, i, dataIn.readInt());
				}
			}
			for(int i =0; i < height; ++i){
				for(int j=0; j< width; ++j){
					middle.setCell(j, i, dataIn.readInt());
				}
			}
			for(int i =0; i < height; ++i){
				for(int j=0; j< width; ++j){
					top.setCell(j, i, dataIn.readInt());
				}
			}
			int numObjects = dataIn.readInt();
			for (int i = 0; i < numObjects; i++) {
				Sprite object = getObject(dataIn);
				result.append(object);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	private Sprite getObject(DataInputStream dataIn) throws IOException {
		String name = dataIn.readUTF();
		int type = dataIn.readInt();
		int x = dataIn.readInt();
		int y = dataIn.readInt();
		int width = dataIn.readInt();
		int height = dataIn.readInt();
		switch (type) {
		case 1:
			return getHero(dataIn, name, x, y, width, height);
		case 2:
			return getWall(name, x, y, width, height);
		case 3:
			return getTalker(dataIn, name, x, y);
		default:
			return null;
		}
	}

	private Sprite getTalker(DataInputStream dataIn, String name, int x, int y) throws IOException {
		byte faceDir = dataIn.readByte();
		String image = dataIn.readUTF();
		String mensage = dataIn.readUTF();
		
		Talker talker = new Talker(Image.createImage("/sprites/"+image+".png"), Engine.TILESIZE, Engine.TILESIZE, x, y);
		talker.setGridPosition(x, y);
		talker.align2Grig();
		
		talker.setFaceDir(faceDir);
		talker.setMensage(mensage);
		
		return talker;
	}

	private Sprite getWall(String name, int x, int y, int width, int height) {
		return new Wall(x*Engine.TILESIZE, y*Engine.TILESIZE, width*Engine.TILESIZE, height*Engine.TILESIZE);
	}

	private Sprite getHero(DataInputStream dataIn, String name, int x, int y, int width, int height) throws IOException {
		Hero result = new Hero(Image.createImage("/sprites/girlie.png"), Engine.TILESIZE, Engine.TILESIZE, x, y);
//		result.setPosition(x*MyGameCanvas.TILESIZE, y*MyGameCanvas.TILESIZE);
		result.setGridPosition(x, y);
		result.align2Grig();
		byte faceDir = dataIn.readByte();
		result.setFaceDir(faceDir);
		return result;
	}
	
}
